home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 2 / Amiga Tools 2.iso / tools / mg / src.lzh / amiga / ttyio.c < prev    next >
C/C++ Source or Header  |  1990-05-23  |  29KB  |  1,218 lines

  1. /*
  2.  * Name:    MG 2a Amiga terminal window I/O, with all kinds o' trimmings.
  3.  * This module is 'way too big. Last Edit:    01-Dec-87
  4.  * mic@emx.cc.utexas.edu Created:    21-Apr-86 mic@emx.cc.utexas.edu
  5.  */
  6.  
  7. #undef    MANX
  8. #undef    LATTICE
  9. #include "rexx.h"
  10. #include "no_dir.h"
  11. #include "compiler.h"
  12. #include "change_font.h"
  13. #include "v11.h"
  14. #include "mouse.h"
  15. #include "no_metakey.h"
  16. #include "promptwait.h"
  17. #include "nrow.h"
  18. #include "ncol.h"
  19. #include "init_cols.h"
  20. #include "init_rows.h"
  21. #include "do_menu.h"
  22. #ifndef    NO_METAKEY
  23. #include "metabit.h"
  24. #endif
  25. #include "use_arp.h"
  26. #ifdef    USE_ARP
  27. #include <arpfunctions.h>
  28. #endif
  29.  
  30. /*
  31.  * Lots of includes.
  32.  */
  33.  
  34. #include <exec/types.h>
  35. #include <exec/nodes.h>
  36. #include <exec/lists.h>
  37. #include <exec/tasks.h>
  38. #include <exec/ports.h>
  39. #include <exec/io.h>
  40. #include <devices/console.h>
  41. #include <devices/inputevent.h>
  42. #include <libraries/dos.h>
  43. #include <libraries/dosextens.h>
  44. #include <graphics/clip.h>
  45. #include <graphics/view.h>
  46. #include <graphics/rastport.h>
  47. #include <graphics/layers.h>
  48. #include <graphics/text.h>
  49. #include <graphics/gfxbase.h>
  50. #include <intuition/intuition.h>
  51. #include <intuition/intuitionbase.h>
  52.  
  53. #undef TRUE
  54. #undef FALSE
  55. #include "def.h"        /* includes sysdef.h and ttydef.h     */
  56. #include "window.h"
  57.  
  58. #ifdef    REXX
  59. #include "key.h"
  60. #endif
  61.  
  62. #ifdef    CHANGE_FONT
  63. #include <libraries/diskfont.h>
  64. #endif
  65.  
  66. #ifdef LATTICE
  67. #ifdef    CHANGE_FONT
  68. #include <proto/diskfont.h>
  69. #endif
  70. #include <proto/exec.h>
  71. #include <proto/dos.h>
  72. #include <proto/graphics.h>
  73. #include <proto/intuition.h>
  74. #include <proto/console.h>
  75. #else
  76. #include <functions.h>
  77. #endif
  78.  
  79. #ifdef    ANSI
  80. #include <string.h>
  81. #include <stdlib.h>
  82. #endif
  83.  
  84. #ifdef USE_ARP
  85. struct ArpBase *ArpBase;
  86. #endif
  87. struct IntuitionBase *IntuitionBase;
  88. struct GfxBase *GfxBase;
  89.  
  90. #ifndef    NO_DIR
  91. extern struct Task *FindTask();
  92. static BPTR     StartLock;
  93. char            WindowTitle[MAXPATH + 20], *MyDirName;
  94. #ifndef MANX
  95. extern BPTR     DupLock(), CurrentDir();
  96. #endif
  97. #endif                /* NO_DIR */
  98. #ifdef    DO_MENU
  99. extern struct Menu *InitEmacsMenu();
  100. #endif
  101.  
  102. #ifndef    LATTICE
  103. extern int      Enable_Abort;    /* Do NOT allow abort!         */
  104. #endif
  105.  
  106. /*
  107.  * External MG functions and variables
  108.  */
  109. extern char     version[];    /* Version information         */
  110. extern int      ttrow;        /* Current cursor row         */
  111. extern int      use_metakey;    /* Do meta characters?         */
  112.  
  113. /*
  114.  * My own, internal functions
  115.  */
  116. static VOID amigaclean PROTO((void));
  117. static void setmaxima PROTO((void));
  118. static struct Screen *wbscreen PROTO((void));
  119. static void ttreopen PROTO((int resize));
  120. static int handle_kbd PROTO((int timeout));
  121. static int dispatch PROTO((struct IntuiMessage * msg));
  122. static int nextkey PROTO((void));
  123. static void qkey PROTO((short k));
  124. #ifdef    MOUSE
  125. static void qmouse PROTO((short x, short y, unsigned short qual));
  126. #endif
  127. #ifdef    DO_MENU
  128. static void qmenu PROTO((unsigned short code));
  129. #endif
  130.  
  131. #ifdef MANX
  132. /* these are in localproto.h, but this is not included for MANX3.6 */
  133. VOID    ttclose();
  134. VOID    setttysize();
  135. VOID    syscleanup();
  136. VOID    ttflush();
  137. VOID    panic();
  138. #endif
  139. /*
  140.  * Library bases (used by glue libraries)
  141.  */
  142.  
  143. #ifndef    LATTICE
  144. #ifdef    CHANGE_FONT
  145. struct DiskFontBase * DiskfontBase;
  146. #endif
  147. #endif
  148.  
  149. /*
  150.  * Intuition window and menu variables.  MG gets used a lot, because it gets
  151.  * reconfigured on the fly for the amiga-set-font and toggle-border
  152.  * operations.
  153.  */
  154.  
  155. #define WINDOWGADGETS (WINDOWDRAG | WINDOWDEPTH | WINDOWCLOSE)
  156. #define WINDOWFLAGS    (WINDOWGADGETS | ACTIVATE)
  157.  
  158. struct NewWindow MG = {
  159.     0, 0,            /* start position            */
  160.     0, 0,            /* width, height (set by ttopen) */
  161.     0, 1,            /* detail pen, block pen     */
  162. #ifdef    DO_MENU
  163.     MENUPICK |        /* If menu is used         */
  164. #endif
  165. #ifdef    MOUSE
  166.     MOUSEBUTTONS |        /* If mouse is used         */
  167. #endif
  168.     INTUITICKS | RAWKEY |
  169.     CLOSEWINDOW | NEWSIZE,    /* IDCMP flags             */
  170.     0,            /* window flags    (set by ttopen)     */
  171.     NULL,            /* pointer to first user gadget */
  172.     NULL,            /* pointer to user checkmark     */
  173.     NULL,            /* title (filled in later)     */
  174.     NULL,            /* pointer to screen (none)     */
  175.     NULL,            /* pointer to superbitmap     */
  176.     220, 40,        /* minimum size    (small!)     */
  177.     0, 0,            /* maximum size (set by ttopen)     */
  178.     WBENCHSCREEN        /* screen in which to open     */
  179. };
  180.  
  181. static short    borderless = TRUE;    /* Flag for borderless window     */
  182. static short    toggle_zooms = TRUE;    /* Does toggling border zoom?     */
  183. static int      last_top, last_left, last_height, last_width;
  184.  
  185. struct Window  *EmW = NULL;    /* Our window             */
  186. struct Screen  *EmS = NULL;    /* Our screen (usually WB)     */
  187. short           toggling = FALSE;    /* Prevent menu wiping         */
  188. #ifndef    V11
  189. struct Screen   WBInfo;        /* Info about the WB screen     */
  190. #endif
  191. struct TextFont *EmFont = NULL;    /* Our font (usually TOPAZ_xx)     */
  192.  
  193. #ifdef    DO_MENU
  194. static struct Menu *EmacsMenu = NULL;    /* Our menu         */
  195. #endif
  196.  
  197. #if    0
  198. static ULONG    class;        /* Intuition event     */
  199. static USHORT   code,        /* information     */
  200.                 qualifier;
  201. static APTR     address;
  202. static SHORT    x, y;
  203. #endif    /* 0 */
  204. static LONG     intuitionMsgMask;/* Signal Mask         */
  205.  
  206. /* * * * * * * * * * * * * console I/O * * * * * * * * * * * * * * * * */
  207.  
  208. #define    CSI    0x9b        /* Command Sequence Introducer     */
  209. #define    NOBUF    512        /* About 1/4 screen         */
  210. #define    NIBUF    256        /* Input buffer             */
  211.  
  212. static KCHAR    ibuf[NIBUF];    /* keyboard input buffer     */
  213. static int      ibufo, nibuf;    /* head, # of bytes in ibuf     */
  214.  
  215. static LONG     tickcount;    /* # intuiticks    since last char     */
  216.  
  217. static struct MsgPort *conWritePort = NULL;    /* I/O ports          */
  218. static struct IOStdReq *conWriteMsg = NULL;    /* I/O messages         */
  219. struct Library *ConsoleDevice;    /* used by RawKeyConvert */
  220. static unsigned char outbuf[NOBUF + 7];    /* output buffer     */
  221. static unsigned char *obuf;    /* first output char     */
  222. int             nobuf;        /* # of bytes in above     */
  223. int             nrow;        /* Terminal size, rows.     */
  224. int             ncol;        /* Terminal size, cols.     */
  225.  
  226. /* * * * * * * * * functions to open/reopen the window * * * * * * * * * */
  227.  
  228. /*
  229.  * Open up the virtual terminal MG communicates with. Set up the window,
  230.  * console, and menu strip.
  231.  */
  232.  
  233. ttopen()
  234. {
  235.  
  236. #ifndef    LATTICE
  237.     Enable_Abort = 0;    /* Disable ^C     */
  238. #endif
  239.  
  240.     /* Set the window size, set the flags and title, and open it */
  241.  
  242.     setmaxima();
  243.     MG.Flags = WINDOWFLAGS;
  244.     MG.Flags |= borderless ? BORDERLESS : WINDOWSIZING;
  245. #ifndef    NO_DIR
  246.     MG.Title = (UBYTE *) WindowTitle;
  247. #else
  248.     MG.Title = (UBYTE *) version;
  249. #endif
  250.  
  251.     if ((EmW = OpenWindow(&MG)) == NULL)
  252.         amigaclean();
  253.     SetFont(EmW->RPort, EmFont);
  254.  
  255.     /*
  256.      * Once the window is created, get the Intuition signal bit, set up
  257.      * the menu, and tell the virtual terminal how big it is.
  258.      */
  259.     setttysize();
  260.     intuitionMsgMask = 1L << EmW->UserPort->mp_SigBit;
  261. #ifdef    DO_MENU
  262.     if (toggling == FALSE)
  263.         EmacsMenu = InitEmacsMenu(EmW);
  264.     if (EmacsMenu == NULL)
  265.         amigaclean();
  266.     SetMenuStrip(EmW, EmacsMenu);
  267. #endif
  268.  
  269.     /*
  270.      * Attach a console device (purely for output now) to our window
  271.      */
  272.  
  273.     if ((conWritePort = CreatePort("Emacs.con.write", 0L)) == NULL)
  274.         amigaclean();
  275.     if ((conWriteMsg = CreateStdIO(conWritePort)) == NULL)
  276.         amigaclean();
  277.  
  278.     if (OpenConsole(conWriteMsg, NULL, EmW) != 0)
  279.         amigaclean();
  280.  
  281.     ConsoleDevice = (struct Library *) conWriteMsg->io_Device;
  282.     nibuf = ibufo = 0;
  283.  
  284.     return (0);
  285. }
  286.  
  287. /*
  288.  * Set up the initial state of the window.  Opens up libraries, decides how
  289.  * big the initial window should be, and whether it should be borderless.
  290.  */
  291.  
  292. VOID
  293. sysinit()
  294. {
  295. #ifndef    NO_DIR
  296.     long            len;
  297.     BPTR            MyDirLock;
  298. #endif
  299.  
  300.     GfxBase = (struct GfxBase *) OpenLibrary("graphics.library", 0L);
  301.     if (GfxBase == NULL)    /* Graphics lib     */
  302.         amigaclean();
  303.  
  304.     IntuitionBase = (struct IntuitionBase *)    /* Intuition     */
  305.         OpenLibrary("intuition.library", 0L);
  306.     if (IntuitionBase == NULL)
  307.         amigaclean();
  308.  
  309. #ifdef USE_ARP
  310.     if (!(ArpBase = (struct ArpBase *) OpenLibrary("arp.library", 0L)))
  311.         panic("Compiled with USE_ARP, but arp.library not found");
  312. #endif
  313. #ifdef    REXX
  314.     openrexx();
  315. #endif
  316. #ifndef NO_DIR
  317.     /*
  318.      * The following attempt to be clever assigns the external StartLock
  319.      * to the lock on the current directory, then switches our CurrentDir
  320.      * to a duplicate of that lock so we can restore the original lock on
  321.      * exit.
  322.      */
  323.  
  324.     strcpy(WindowTitle, version);
  325.     strcat(WindowTitle, ": ");
  326.     MyDirName = strchr(WindowTitle, '\0');
  327.     StartLock = ((struct Process *) FindTask(0L))->pr_CurrentDir;
  328.     (void) CurrentDir(MyDirLock = DupLock(StartLock));
  329.     len = PathName(MyDirLock, MyDirName, MAXPATH);
  330. #endif                /* NO_DIR */
  331.  
  332. #ifdef    CHANGE_FONT
  333. #ifndef    LATTICE
  334.     DiskfontBase = (struct DiskFontBase *) OpenLibrary("diskfont.library", 0L);
  335. #else
  336.     DiskfontBase = OpenLibrary("diskfont.library", 0L);
  337. #endif
  338.     if (DiskfontBase == NULL)
  339.         amigaclean();
  340. #endif
  341.  
  342.     /* Get our screen and font, then figure out if we can go borderless */
  343.     if ((EmS = wbscreen()) == NULL)
  344.         amigaclean();
  345. #ifdef    CHANGE_FONT
  346.     EmFont = OpenDiskFont(EmS->Font);
  347. #else
  348.     EmFont = OpenFont(EmS->Font);
  349. #endif
  350.     if ((EmS->Width >= ((INIT_COLS * EmFont->tf_XSize) + LR_BORDER)) &&
  351.         (EmS->Height >= ((INIT_ROWS * EmFont->tf_YSize) + TB_BORDER)))
  352.         borderless = FALSE;
  353.  
  354.     /*
  355.      * Set the size of the initial window and fake the last one
  356.      */
  357.     last_width = MG.Width = EmS->Width;
  358.     last_height = MG.Height = EmS->Height;
  359.     last_left = MG.LeftEdge = 0;
  360.     last_top = MG.TopEdge = 0;
  361.  
  362.     strcpy(outbuf, "\x9b" "0 p");    /* preload cursor off sequence */
  363.     obuf = outbuf + 4;
  364. }
  365.  
  366. /*
  367.  * Make sure the window isn't bigger than NROW * NCOL, while accounting for
  368.  * borders & such.  Since the window might not be at its largest right now,
  369.  * deadstop both the current width and the maxwidth.
  370.  */
  371.  
  372. static VOID 
  373. setmaxima()
  374. {
  375.     register int    maxw, maxh;
  376.  
  377.     MG.MaxWidth = EmS->Width;
  378.     MG.MaxHeight = EmS->Height;
  379.     maxw = NCOL * EmFont->tf_XSize + (borderless ? 0 : LR_BORDER);
  380.     maxh = NROW * EmFont->tf_YSize + (borderless ? TOP_OFFSET : TB_BORDER);
  381.  
  382.     if (MG.MaxWidth > maxw)
  383.         MG.MaxWidth = maxw;
  384.     if (MG.Width > maxw)
  385.         MG.Width = maxw;
  386.  
  387.     if (MG.MaxHeight > maxh)
  388.         MG.MaxHeight = maxh;
  389.     if (MG.Height > maxh)
  390.         MG.Height = maxh;
  391. }
  392.  
  393.  
  394. /*
  395.  * Return a pointer the workbench screen, using GetScreenData() to do things
  396.  * like a good citizen.  Left the V11 code in as a reminder that what works
  397.  * is not always the _best_ way to do things. Thanks to Tom Rokicki for
  398.  * reminding me (mpk) this had to be done.
  399.  */
  400.  
  401. static struct Screen
  402.                *
  403. wbscreen()
  404. {
  405. #ifndef    V11
  406.     return GetScreenData((char *) &WBInfo, (long) sizeof(WBInfo),
  407.            WBENCHSCREEN, NULL) ? &WBInfo : ((struct Screen *) NULL);
  408. #else
  409.     register struct Screen *s;
  410.     Forbid();
  411.     for (s = IntuitionBase->FirstScreen; s; s = s->NextScreen)
  412.         if ((s->Flags & SCREENTYPE) == WBENCHSCREEN)
  413.             break;
  414.     Permit();
  415.     return (s);
  416. #endif
  417. }
  418.  
  419. /*
  420.  * Hide the window and open it up again.  If resize is TRUE, they're being
  421.  * called as part of a resize operation, so assume that the NewWindow
  422.  * structure is set correctly.  Otherwise, store the current window size and
  423.  * position in the NewWindow structure.
  424.  * 
  425.  * These two functions are split so we can do things like ttreopen() and
  426.  * tticon() cleanly.
  427.  */
  428.  
  429. VOID
  430. tthide(resize)
  431.     int             resize;
  432. {
  433.     toggling = TRUE;
  434.     if (resize == FALSE) {    /* if we're resizing,     */
  435.         MG.LeftEdge = EmW->LeftEdge;    /* use current window size     */
  436.         MG.TopEdge = EmW->TopEdge;
  437.         MG.Width = EmW->Width;
  438.         MG.Height = EmW->Height;
  439.     }
  440.     ttclose();        /* reset to zero     */
  441. }
  442.  
  443. VOID
  444. ttshow(resize)
  445.     int             resize;
  446. {
  447.     ttopen();        /* re-open tty window     */
  448.     ttinit();        /* re-initalize tty     */
  449.     sgarbf = TRUE;        /* screen was trashed     */
  450.     if (resize == TRUE)
  451.         nrow = ncol = -1;    /* trash screen size     */
  452.     refresh(FFARG, 1);    /* and redraw it     */
  453.     toggling = FALSE;    /* Ok, done         */
  454. }
  455.  
  456. /*
  457.  * ttreopen() was split into the two functions above when tticon() was
  458.  * introduced.
  459.  */
  460.  
  461. static          VOID
  462. ttreopen(resize)
  463.     int             resize;
  464. {
  465.     tthide(resize);
  466.     ttshow(resize);
  467. }
  468.  
  469. /* * * * * * * * * * * * functions to close the window * * * * * * * * */
  470.  
  471. /*
  472.  * Close the virtual terminal.  If toggling, don't release all the other
  473.  * resources we've allocated.
  474.  */
  475. VOID
  476. ttclose()
  477. {
  478.     ttflush();
  479.     if (conWriteMsg!=NULL) {
  480.         CloseDevice((struct IORequest *) conWriteMsg);
  481.         DeleteStdIO(conWriteMsg);
  482.         conWriteMsg = NULL;
  483.     }
  484.     if (conWritePort!=NULL) {
  485.         DeletePort(conWritePort);
  486.         conWritePort = NULL;
  487.     }
  488.     if (EmW!=NULL) {
  489. #ifdef    DO_MENU
  490.         ClearMenuStrip(EmW);
  491. #endif
  492.         CloseWindow(EmW);
  493.         EmW=NULL;
  494.     }
  495. #ifndef    LATTICE
  496.     Enable_Abort = 1;
  497. #endif
  498. }
  499.  
  500. /*
  501.  * To explain the many paths out of mg:
  502.  * 
  503.  * ttclose: Shuts down the window & associated IO devices. This gets called to
  504.  * go to a "quiescent" state - iconified, or waiting for rexx.
  505.  * 
  506.  * syscleanup: Closes everything, in preperation for shutting down permanently.
  507.  * 
  508.  * amigaclean: Calls the above two routines in order, then exits quietly Used
  509.  * when we're not up yet, and something fails to open.
  510.  * 
  511.  * panic: Displays a message in the echo area, then does an amigaclean. Used to
  512.  * die in emergencies from an up state.
  513.  */
  514.  
  515. /*
  516.  * Shut 'er down scotty, she's sucking mud! Usefull even when we're not all
  517.  * the way up yet.
  518.  */
  519. VOID
  520. amigaclean()
  521. {
  522.     ttclose();
  523.     syscleanup();
  524.     exit(20);
  525. }
  526.  
  527. /*
  528.  * System dependent cleanup for the Amiga.
  529.  */
  530. VOID
  531. syscleanup()
  532. {
  533. #ifdef    REXX
  534.     closerexx();
  535. #endif
  536. #ifndef    NO_DIR
  537.     UnLock(CurrentDir(StartLock));    /* restore startup directory     */
  538. #endif
  539.  
  540.     if (conWriteMsg)
  541.         DeleteStdIO(conWriteMsg);
  542.     if (conWritePort)
  543.         DeletePort(conWritePort);
  544. #ifdef    DO_MENU
  545.     if (EmacsMenu)
  546.         DisposeMenus();
  547. #endif
  548.     if (EmFont)
  549.         CloseFont(EmFont);
  550. #ifdef    CHANGE_FONT
  551.     if (DiskfontBase)
  552.         CloseLibrary((struct Library *) DiskfontBase);
  553. #endif
  554.     if (IntuitionBase)
  555.         CloseLibrary((struct Library *) IntuitionBase);
  556.     if (GfxBase)
  557.         CloseLibrary((struct Library *) GfxBase);
  558. #ifdef USE_ARP
  559.     if (ArpBase)
  560.         CloseLibrary((struct Library *) ArpBase);
  561. #endif
  562.  
  563. }
  564.  
  565. /* * * * * * * * functions that diddle the window and reopen it * * * * * */
  566.  
  567. /*
  568.  * Toggle between a borderless window and a sizeable window. This lets you
  569.  * use the whole screen if you want. Bound to "amiga-toggle-border".
  570.  */
  571.  
  572. togglewindow(f, n)
  573. {
  574.  
  575.     if ((borderless = !borderless) == TRUE) {    /* *always* save last     */
  576.         last_top = EmW->TopEdge;    /* bordered window size     */
  577.         last_left = EmW->LeftEdge;
  578.         last_width = EmW->Width;
  579.         last_height = EmW->Height;
  580.     }
  581.     if (toggle_zooms == FALSE) {    /* just use current size */
  582.         ttreopen(FALSE);
  583.         return (TRUE);
  584.     }
  585.     /*
  586.      * zooming -- if borderless, go as big as possible.  If bordered, set
  587.      * to last saved value of bordered window
  588.      */
  589.     if (borderless) {
  590.         MG.LeftEdge = 0;
  591.         MG.TopEdge = 0;
  592.         MG.Width = MG.MaxWidth;
  593.         MG.Height = MG.MaxHeight;
  594.     } else {
  595.         MG.LeftEdge = last_left;
  596.         MG.TopEdge = last_top;
  597.         MG.Width = last_width;
  598.         MG.Height = last_height;
  599.     }
  600.     ttreopen(TRUE);        /* open with new size     */
  601.     return (TRUE);
  602. }
  603.  
  604. /*
  605.  * Modify the action of "amiga-toggle-border", reporting outcome to user.
  606.  * Bound to "amiga-zoom-mode".
  607.  */
  608. togglezooms(f, n)
  609. {
  610.     toggle_zooms = !toggle_zooms;
  611.     ewprintf("Toggling border %s",
  612.          toggle_zooms ? "expands window to screen size" :
  613.          "retains current window size");
  614.     return (TRUE);
  615. }
  616.  
  617. #ifdef    CHANGE_FONT
  618. /*
  619.  * Select a different font for the MG window. This does not work very well
  620.  * with proportional fonts, so we ask the user to confirm before he uses one.
  621.  * It's available if you want to be able to use your own disk font (or Topaz
  622.  * 11 under 1.2) to edit with.
  623.  */
  624.  
  625. setfont(f, n)
  626. {
  627.     register int    s, size;
  628.     register struct TextFont *newfont;
  629.     char            fontname[80], fontpath[84], fontsize[3];
  630.     struct TextAttr ta;
  631.  
  632.     /*
  633.      * If negative size, reset to default font
  634.      */
  635.     if ((f & FFARG) && (n <= 0)) {
  636.         CloseFont(EmFont);    /* return old font  */
  637.         EmFont = OpenDiskFont(EmS->Font);    /* screen's default */
  638.         ttreopen(TRUE);    /* we changed fonts, so resize        */
  639.         ewprintf("Now using default font");
  640.         return (TRUE);
  641.     }
  642.     if ((s = ereply("Font name: ", fontname, sizeof(fontname))) != TRUE)
  643.         return (s);
  644.     strcpy(fontpath, fontname);
  645.     strncat(fontpath, ".font", sizeof(fontpath));    /* make name */
  646.  
  647.     /* Get font size */
  648.     if (f & FFARG)
  649.         size = n;
  650.     else {
  651.         if ((s = ereply("Font size: ",
  652.                 fontsize, sizeof(fontsize))) != TRUE)
  653.             return (s);
  654.         size = atoi(fontsize);
  655.     }
  656.  
  657.     /* Set up text attributes */
  658.     ta.ta_Name = (UBYTE *) fontpath;
  659.     ta.ta_YSize = size;
  660.     ta.ta_Style = FS_NORMAL;
  661.     ta.ta_Flags = 0;
  662.  
  663.     /* Look for the font */
  664.     ewprintf("Looking for %s %d...", fontname, size);
  665.     if ((newfont = OpenDiskFont(&ta)) == NULL) {
  666.         ewprintf("Can't find %s %d!", fontname, size);
  667.         return (FALSE);
  668.     }
  669.     /* Found it! Check before using it */
  670.     if ((newfont->tf_YSize != size) &&
  671.         ((s = eyesno("Size unavailable - use closest")) != TRUE)) {
  672.         CloseFont(newfont);
  673.         return (FALSE);
  674.     }
  675.     if ((newfont->tf_Flags & FPF_PROPORTIONAL) &&
  676.         (((s = eyesno("Use proportional font"))) != TRUE)) {
  677.         CloseFont(newfont);
  678.         return (FALSE);
  679.     }
  680.     /* Get rid of old font and reopen with the new one */
  681.     CloseFont(EmFont);
  682.     EmFont = newfont;
  683.     ttreopen(TRUE);    /* Different font sizes means we may need to resize */
  684.     ewprintf("Now using font %s %d", fontname, EmFont->tf_YSize);
  685.     return (TRUE);
  686. }
  687. #endif
  688.  
  689. /* * * * * * * * * * * * * console output functions  * * * * * * * * * * * * */
  690.  
  691. /*
  692.  * Write a single character to the screen. Buffered for speed, so ttflush()
  693.  * does all the work.
  694.  */
  695. VOID
  696. #ifdef NO_PROTO
  697. ttputc(c)
  698.     unsigned char    c;
  699. #else
  700. ttputc PROTO((unsigned char c))
  701. #endif
  702. {
  703.     obuf[nobuf++] = c;
  704.     if (nobuf >= NOBUF)
  705.         ttflush();
  706. }
  707.  
  708. /*
  709.  * Flush characters from the output buffer.  If the # of characters is
  710.  * greater than a certain ad-hoc value, turn the cursor off while doing the
  711.  * write. To avoid extra writes, the output buffer has been preloaded with
  712.  * the cursor-off sequence.  Outbuf is large enough to hold the extra 7
  713.  * characters.
  714.  */
  715. #define    MIN_OFF    8
  716. VOID
  717. ttflush()
  718. {
  719.     if (nobuf > 0) {
  720.         if (nobuf <= MIN_OFF)    /* don't turn off for short writes */
  721.             ConWrite(conWriteMsg, obuf, nobuf);
  722.         else {
  723.             obuf[nobuf++] = '\x9b';
  724.             obuf[nobuf++] = ' ';
  725.             obuf[nobuf++] = 'p';
  726.             ConWrite(conWriteMsg, outbuf, nobuf + 4);
  727.         }
  728.         nobuf = 0;
  729.     }
  730. }
  731.  
  732. /*
  733.  * The caller intends to output an escape sequence, but only flush the buffer
  734.  * if there's not enough room to hold the complete sequence. This avoids
  735.  * breaking up escape sequences when we turn the cursor off in ttflush(), at
  736.  * the expense of some extra function calls.
  737.  */
  738. VOID 
  739. ttnflush(n)
  740.     int             n;
  741. {
  742.     if ((nobuf + n) > NOBUF)
  743.         ttflush();
  744. }
  745.  
  746. /* * * * * * * * * * * * * console input functions  * * * * * * * * * * * * */
  747.  
  748. /*
  749.  * Read a character (really a KCHAR, > 8 bits), blocking till a character is
  750.  * put in the input buffer and can be returned.
  751.  */
  752. ttgetc()
  753. {
  754.     return handle_kbd(FALSE);
  755. }
  756.  
  757. /*
  758.  * Return TRUE if we've waited for 2 seconds and nothing has happened, else
  759.  * return false.
  760.  */
  761.  
  762. ttwait()
  763. {
  764.     return handle_kbd(TRUE);/* time out after 2 sec */
  765. }
  766.  
  767. /*
  768.  * Common routine for handling character input, with and without timeout.
  769.  * Handle events until:
  770.  * 
  771.  * 1) a character is put in the input buffer 2) if timeout == TRUE, PROMPTWAIT
  772.  * IntuiTicks have gone by
  773.  * 
  774.  * If timeout == FALSE, the input character is returned and removed from the
  775.  * input buffer.
  776.  * 
  777.  * If timeout == TRUE, returns TRUE if the read timed out, else FALSE. Leaves
  778.  * any character typed in the input buffer.
  779.  */
  780.  
  781. static 
  782. handle_kbd(timeout)
  783.     register int    timeout;
  784. {
  785.     register struct IntuiMessage *message;    /* IDCMP message      */
  786.     register LONG   wakeupmask;    /* which signals?     */
  787.     register int    charfound;    /* got a character yet?     */
  788. #ifdef    REXX
  789.     struct key      savekey;/* Save current keystrokes */
  790.     extern struct MsgPort *rexxport;    /* Bit to check for Rexx msgs */
  791.     register int    rexxbit = 1l << rexxport->mp_SigBit;
  792. #endif
  793.  
  794.     tickcount = 0;        /* *always* zero the count */
  795.     if (nibuf)        /* any chars? return if so */
  796.         return timeout ? FALSE : nextkey();
  797.  
  798.     charfound = FALSE;    /* nope -- have to wait     */
  799.     do {
  800.         wakeupmask = Wait(intuitionMsgMask
  801. #ifdef    REXX
  802.                   | rexxbit
  803. #endif
  804.             );
  805.  
  806. #ifdef        REXX
  807.         /* Now handle any rexx messages if we need them */
  808.         if (wakeupmask & rexxbit) {
  809.             savekey = key;
  810.             disprexx(rexxport);
  811.             update();
  812.             key = savekey;
  813.         }
  814. #endif
  815.  
  816.         /* Handle Intuiticks specially for speed */
  817.         while (message = (struct IntuiMessage *) GetMsg(EmW->UserPort))
  818.             if (message->Class == INTUITICKS) {
  819.                 tickcount++;
  820.                 ReplyMsg((struct Message *) message);
  821.             } else if (dispatch(message) == TRUE)
  822.                 charfound = TRUE;
  823.  
  824.  
  825.         /*
  826.          * time out if enough ticks have gone by without any keyboard
  827.          * input.  We do this *after* all the events in the current
  828.          * list have been dispatched.
  829.          */
  830.         if (timeout && (tickcount > PROMPTWAIT))
  831.             break;
  832.     } while (charfound == FALSE);
  833.  
  834.  
  835.     /*
  836.      * If called by ttwait(), return FALSE if a character was found. Else
  837.      * return the next character in the input buffer
  838.      */
  839.     return timeout ? (!charfound) : nextkey();
  840. }
  841.  
  842. /*
  843.  * Handle the events we handle...  The result returned indicates if we've put
  844.  * a character in the input buffer.
  845.  */
  846. #ifndef    NO_METAKEY
  847. #define    IEQUALIFIER_ALT        (IEQUALIFIER_RALT | IEQUALIFIER_LALT)
  848. #endif
  849.  
  850. static 
  851. dispatch(msg)
  852.     register struct IntuiMessage *msg;
  853. {
  854. #ifdef    DO_MENU
  855.     register struct MenuItem *item;
  856. #endif
  857.  
  858.     register int    txheight, txwidth;
  859.     register struct RastPort *rp;
  860.     int             dx, dy, fgpen, drmode;
  861.  
  862.     static struct InputEvent FakedEvent = {NULL, IECLASS_RAWKEY, 0, 0, 0};
  863. #ifndef    NO_METAKEY
  864.     unsigned char   altbuf[64];
  865.     int             altlen;
  866. #endif
  867.     unsigned char   keybuf[64];
  868.     int             keylen, i;
  869. #ifndef    V11
  870.     APTR            deadcodes;
  871. #endif
  872.     ULONG        class;
  873.     USHORT        code,
  874.             qualifier;
  875.     APTR        address;
  876.     SHORT        x, y;
  877.  
  878.     class = msg->Class;    /* grab the info before we      */
  879.     code = msg->Code;    /* reply to the message         */
  880.     qualifier = msg->Qualifier;
  881.     address = msg->IAddress;
  882.     x = msg->MouseX;
  883.     y = msg->MouseY;
  884. #ifndef    V11
  885.     if (class == RAWKEY)    /* get dead key info         */
  886.         deadcodes = (APTR) * address;
  887. #endif
  888.     ReplyMsg((struct Message *) msg);    /* return it to Intuition     */
  889.  
  890.     switch (class) {    /* see what the fuss is about     */
  891.     case RAWKEY:
  892.         FakedEvent.ie_Code = code;
  893.         FakedEvent.ie_Qualifier = qualifier;
  894. #ifndef    V11
  895.         FakedEvent.ie_EventAddress = deadcodes;
  896. #endif
  897.         keylen = (int) RawKeyConvert(&FakedEvent,
  898.                        keybuf, (LONG) sizeof(keybuf), NULL);
  899.  
  900. #ifndef NO_METAKEY
  901.         /*
  902.          * Special mapping for ALT-ed keys.  The intent is to allow
  903.          * extended ASCII characters that are generated without the
  904.          * ALT key to pass unscathed through getkbd(). However, if
  905.          * METABIT is 0x80 & use_metaky is on, they will get changed
  906.          * by getkey(). Hence, Amiga mg should be compiled with
  907.          * METABIT being 0x80.
  908.          */
  909.         if ((qualifier & IEQUALIFIER_ALT) && use_metakey) {
  910.             FakedEvent.ie_Qualifier &= ~IEQUALIFIER_ALT;
  911.             altlen = (int) RawKeyConvert(&FakedEvent, altbuf,
  912.                            (LONG) sizeof(altbuf), NULL);
  913.             if (altlen >= 1)
  914.                 qkey((KCHAR) (METABIT | altbuf[0]));
  915.             for (i = 1; i < altlen; i++)
  916.                 qkey((KCHAR) altbuf[i]);
  917.             return (altlen > 0) ? TRUE : FALSE;
  918.         }
  919. #endif
  920.         /* non-ALTed key */
  921.         for (i = 0; i < keylen; i++)
  922.             qkey((KCHAR) keybuf[i]);
  923.         return (keylen > 0) ? TRUE : FALSE;
  924.         break;
  925.  
  926. #ifdef    DO_MENU
  927.     case MENUPICK:
  928.         if (code == MENUNULL)
  929.             return (FALSE);
  930.         while (code != MENUNULL) {    /* handle multiple selection     */
  931.             qmenu(code);
  932.             item = ItemAddress(EmacsMenu, (LONG) code);
  933.             code = item->NextSelect;
  934.         }
  935.         return (TRUE);    /* puts KMENU in event queue     */
  936.         break;
  937. #endif
  938.  
  939. #ifdef    MOUSE
  940.     case MOUSEBUTTONS:    /* fake the mouse key     */
  941.         if (code != SELECTDOWN)    /* ignore SELECTUP     */
  942.             return (FALSE);
  943.         qmouse(x, y, qualifier);
  944.         return (TRUE);
  945.         break;
  946. #endif
  947.  
  948.     case NEWSIZE:
  949.         /*
  950.          * Sometimes when you resize the window to make it smaller,
  951.          * garbage is left at the right and bottom sides of the
  952.          * window. This code is devoted to (somehow) getting rid of
  953.          * this garbage.  Any suggestions?
  954.          */
  955.  
  956.         rp = EmW->RPort;
  957.         fgpen = rp->FgPen;    /* save params         */
  958.         drmode = rp->DrawMode;
  959.         SetDrMd(rp, (LONG) JAM1);
  960.         SetAPen(rp, (LONG) EmW->RPort->BgPen);
  961.  
  962.         /*
  963.          * Check the bottom of the window
  964.          */
  965.         txheight = EmW->Height - EmW->BorderTop - EmW->BorderBottom;
  966.         if (dy = (txheight % FontHeight(EmW)))
  967.             RectFill(rp,
  968.                  (LONG) EmW->BorderLeft,
  969.                  (LONG) EmW->BorderTop + txheight - dy - 1,
  970.                  (LONG) (EmW->Width - 1) - EmW->BorderRight,
  971.                   (LONG) (EmW->Height - 1) - EmW->BorderBottom);
  972.  
  973.         /*
  974.          * Check the right side
  975.          */
  976.         txwidth = EmW->Width - EmW->BorderLeft - EmW->BorderRight;
  977.         if (dx = txwidth % FontWidth(EmW))
  978.             RectFill(rp,
  979.                  (LONG) EmW->BorderLeft + txwidth - dx - 1,
  980.                  (LONG) EmW->BorderTop,
  981.                  (LONG) (EmW->Width - 1) - EmW->BorderRight,
  982.                   (LONG) (EmW->Height - 1) - EmW->BorderBottom);
  983.  
  984.         SetDrMd(rp, (LONG) drmode);
  985.         SetAPen(rp, (LONG) fgpen);    /* restore colors */
  986.  
  987.         /* Tell the console device to resize itself */
  988.         ttputc(CSI);
  989.         ttputc('t');
  990.         ttputc(CSI);
  991.         ttputc('u');
  992.         ttflush();
  993.  
  994.         /*
  995.          * Signal the editor that a new size has occurred. I may
  996.          * break down and do this asynchronously...
  997.          */
  998.         qkey(KRESIZE);
  999.         return (TRUE);    /* we done (finally)     */
  1000.         break;
  1001.  
  1002.     case CLOSEWINDOW:
  1003.         /* Calling quit() directly is not a guaranteed win. */
  1004.         quit(FFRAND, 1);
  1005.         return (FALSE);
  1006.         break;
  1007.  
  1008.     default:
  1009.         panic("HandleMsg: unknown event!!!");
  1010.         break;
  1011.     }
  1012.     return (FALSE);
  1013. }
  1014.  
  1015. /*
  1016.  * Return the current size of the virtual terminal in nrow and ncol, making
  1017.  * sure we don't go beyond the size of the internal video array. Assumes the
  1018.  * current font is monospaced.
  1019.  */
  1020. VOID
  1021. setttysize()
  1022. {
  1023.     nrow = (EmW->Height - TOP_OFFSET
  1024.         - EmW->BorderBottom) / FontHeight(EmW);
  1025.     ncol = (EmW->Width - EmW->BorderLeft
  1026.         - EmW->BorderRight) / FontWidth(EmW);
  1027.     if (nrow < 1)
  1028.         nrow = 1;
  1029.     if (nrow > NROW)
  1030.         nrow = NROW;
  1031.     if (ncol < 1)
  1032.         ncol = 1;
  1033.     if (ncol > NCOL)
  1034.         ncol = NCOL;
  1035. }
  1036.  
  1037. /*
  1038.  * Exit as soon as possible, after displaying the message.
  1039.  */
  1040. VOID
  1041. panic(s)
  1042.     char           *s;
  1043. {
  1044.     ewprintf(s);        /* put message at bottom     */
  1045.     Delay((ULONG) 90);    /* wait 1.5 seconds         */
  1046.     amigaclean();        /* Go Way */
  1047. }
  1048.  
  1049. /*
  1050.  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Event
  1051.  * buffer management         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  1052.  */
  1053.  
  1054. /*
  1055.  * Return next key in the input buffer, if any available.  Returns -1 if not.
  1056.  */
  1057. static int
  1058. nextkey()
  1059. {
  1060.     register KCHAR  k;
  1061.  
  1062.     if (nibuf <= 0) {    /* shouldn't happen, but could... */
  1063.         nibuf = 0;
  1064.         return -1;
  1065.     } else {
  1066.         k = ibuf[ibufo++];
  1067.         nibuf--;
  1068.         ibufo %= NIBUF;
  1069.         return (int) k;
  1070.     }
  1071. }
  1072.  
  1073. /*
  1074.  * Return true if there are some characters available in the input buffer.
  1075.  */
  1076. typeahead()
  1077. {
  1078.     return (nibuf > 0);
  1079. }
  1080.  
  1081. /*
  1082.  * Add a key to the input queue
  1083.  */
  1084. static          VOID
  1085. qkey(k)
  1086.     KCHAR           k;
  1087. {
  1088.     if (nibuf < NIBUF)
  1089.         ibuf[(ibufo + nibuf++) % NIBUF] = k;
  1090. }
  1091.  
  1092. #ifdef    MOUSE
  1093. /*
  1094.  * Add a mouse event to the input queue, calculating the row and column value
  1095.  * from the current height and width of the window's font.
  1096.  */
  1097.  
  1098. static          VOID
  1099. qmouse(x, y, qual)
  1100.     SHORT           x, y;
  1101.     USHORT          qual;
  1102. {
  1103.     register int    myqual = MQ_NOQUAL;
  1104.     register int    row, col;
  1105.     register struct window *wp;
  1106.  
  1107.     /* get row, column     */
  1108.     col = (x - EmW->BorderLeft) / FontWidth(EmW);
  1109.     row = (y - TOP_OFFSET) / FontHeight(EmW);
  1110.  
  1111.     /* find out which kind of window was clicked in */
  1112.     for (wp = wheadp; wp != NULL; wp = wp->w_wndp)
  1113.         if ((row >= wp->w_toprow) &&
  1114.             (row <= (wp->w_toprow + wp->w_ntrows)))
  1115.             break;
  1116.     if (wp == NULL)
  1117.         myqual |= MQ_ECHO;
  1118.     else if (row == (wp->w_toprow + wp->w_ntrows))
  1119.         myqual |= MQ_MODE;
  1120.     else
  1121.         myqual |= MQ_WINDOW;
  1122.  
  1123.     /* figure out qualifiers     */
  1124.     if (qual & IEQUALIFIER_CONTROL)
  1125.         myqual |= MQ_CTRL;
  1126.     if (qual & (IEQUALIFIER_LSHIFT | IEQUALIFIER_LSHIFT))
  1127.         myqual |= MQ_SHIFT;
  1128.     if (qual & (IEQUALIFIER_LALT | IEQUALIFIER_RALT))
  1129.         myqual |= MQ_ALT;
  1130.  
  1131.     /*
  1132.      * Queue up the whole mess.  If user didn't click in the echo line,
  1133.      * transmit the x, y values to the mouse function
  1134.      */
  1135.     qkey((KCHAR) (KW___MOUSE + myqual));
  1136.     if (MQ_WHERE(myqual) != MQ_ECHO) {
  1137.         qkey((KCHAR) (M_X_ZERO + col));
  1138.         qkey((KCHAR) (M_Y_ZERO + row));
  1139.     }
  1140. }
  1141. #endif
  1142.  
  1143. #ifdef    DO_MENU
  1144. /*
  1145.  * Add a menu event to the queue.
  1146.  */
  1147. static          VOID
  1148. qmenu(code)
  1149.     USHORT          code;
  1150. {
  1151.     qkey(KMENU);        /* menu key sequence     */
  1152.     qkey((KCHAR) (MENUNUM(code) + MN_OFFSET));
  1153.     qkey((KCHAR) (ITEMNUM(code) + MN_OFFSET));
  1154.     qkey((KCHAR) (SUBNUM(code) + MN_OFFSET));
  1155. }
  1156. #endif
  1157.  
  1158. void
  1159. sleep(n)
  1160.     int             n;
  1161. {
  1162.     if (n > 0)
  1163.         Delay((long) n * TICKS_PER_SECOND);
  1164. }
  1165.  
  1166. #ifdef MANX
  1167. /* Define some Manx specific functions */
  1168. /*
  1169.  * the only realloc function for MANX 3.6 is in heapmem.o which allocates
  1170.  * storage from a buffer that is fixed in size (read SUCKS ROCKS)!, so 
  1171.  * here is a function that is compatible with the documentation for realloc
  1172.  * that is in MANX 5.0.
  1173.  */
  1174. void *
  1175. realloc(blk, newlen)
  1176. char    *blk;
  1177. int    newlen;
  1178. {
  1179.     char    *nblk;
  1180.  
  1181.     if (newlen == 0) {
  1182.         free(blk);
  1183.         blk=(char *)0;
  1184.         return(blk);
  1185.     } else {
  1186.         nblk = malloc(newlen);
  1187.         if (blk != (char *)0) {
  1188.             movmem(blk, nblk, newlen);
  1189.             free(blk);
  1190.         }
  1191.         blk=nblk;
  1192.     }
  1193.     return(blk);
  1194. }
  1195.  
  1196. /*
  1197.  * Again, MANX doesn't seem to have real useful and regular functions
  1198.  * in the 3.6 release.  Here is a memcmp function for MANX3.6.
  1199.  */
  1200. int
  1201. m_memcmp(s1,s2,l)
  1202. char *s1, *s2;
  1203. int    l;
  1204. {
  1205.     while (l--) {
  1206.     if (*s1==*s2)
  1207.         s1++,s2++;
  1208.     else {
  1209.         if (*s1<*s2) 
  1210.         return -1;
  1211.         else
  1212.         return 1;
  1213.     }
  1214.     }
  1215.     return(0);
  1216. }
  1217. #endif
  1218.